Imports System.Xml

''' <summary>
''' This is my Primary Link List Container Container class
''' Holds the private variables of BikiRom vars, Globals, Fuel, Ign and Extra maps. No additions
''' </summary>
''' <remarks></remarks>
<Serializable(), ObfuscationAttribute(Exclude:=True, ApplyToMembers:=True)> Friend Class Car

    Private m_Bvars As Variables
    Private m_Gvars As Variables
    Private m_Fmaps As Maps
    Private m_Imaps As Maps
    Private m_Emaps As Maps
    Private m_vqMap As Map = Nothing
    Private m_kVar As Variable = Nothing

    Private m_dataStart As Integer = 0
    Private m_dataEnd As Integer = &HFFFF

    Private m_baseData() As Byte
    Private m_mapOne() As Byte = Nothing
    Private m_mapTwo() As Byte = Nothing
    Private m_mapThree() As Byte = Nothing

    Friend Sub New()
        m_Bvars = New Variables("BikiRom Variables")
        m_Gvars = New Variables("Global Variables")
        m_Fmaps = New Maps("Fuel Maps")
        m_Fmaps.setMarginal(128)
        m_Imaps = New Maps("Ignition Maps")
        m_Imaps.setMarginal(197)
        m_Emaps = New Maps("Extra Maps")
        m_Emaps.setMarginal(255)
        m_dataStart = 8192
        m_dataEnd = 65535
    End Sub

    Friend Function getBvars() As Variables
        Return m_Bvars
    End Function
    Friend Function getGvars() As Variables
        Return m_Gvars
    End Function
    Friend Function getFmaps() As Maps
        Return m_Fmaps
    End Function
    Friend Function getImaps() As Maps
        Return m_Imaps
    End Function
    Friend Function getEmaps() As Maps
        Return m_Emaps
    End Function
    Friend Function getVqMap() As Map
        Return m_vqMap
    End Function
    Friend Function getDataStart() As Integer
        Return m_dataStart
    End Function
    Friend Function getDataEnd() As Integer
        Return m_dataEnd
    End Function

    Friend Function mapImport(ByRef Array_() As Byte, ByVal MapNo As Byte) As Boolean
        Dim f_totalLength As Integer = 0
        Dim f_toArray() As Byte = Nothing
        Dim f_length As Integer
        Dim f_offset As Integer = 0

        If MapNo >= 0 And MapNo <= 2 And UBound(Array_) >= (m_dataEnd - 1) Then
            f_totalLength += m_Gvars.length + m_Fmaps.length + m_Imaps.length + m_Emaps.length
            Select Case (MapNo)
                Case 0
                    ReDim m_mapOne(0 To f_totalLength - 1)
                    f_toArray = m_mapOne
                Case 1
                    ReDim m_mapTwo(0 To f_totalLength - 1)
                    f_toArray = m_mapTwo
                Case 2
                    ReDim m_mapThree(0 To f_totalLength - 1)
                    f_toArray = m_mapThree
            End Select

            If Not IsNothing(f_toArray) Then
                Dim f_mapArray() As Map = m_Fmaps.getAsArray
                Dim f_varArray() As Variable = m_Gvars.getAsArray
                Dim f_vq As Map = m_vqMap

                '' Fuel Maps First
                If Not IsNothing(f_mapArray) Then
                    For Each f_ptMap As Map In f_mapArray
                        f_length = f_ptMap.getLength
                        If f_length <> 0 Then
                            array_copy(f_ptMap.getMap(Array_), 0, f_toArray, f_offset, f_length)
                            f_offset += f_length
                        End If
                    Next
                End If
                Console.WriteLine("past the fuel")
                '' Igntiion Maps Second
                f_mapArray = m_Imaps.getAsArray
                If Not IsNothing(f_mapArray) Then
                    For Each f_ptMap As Map In f_mapArray
                        f_length = f_ptMap.getLength
                        If f_length <> 0 Then
                            array_copy(f_ptMap.getMap(Array_), 0, f_toArray, f_offset, f_length)
                            f_offset += f_length
                        End If
                    Next
                End If
                Console.WriteLine("past the ign")
                '' Extra Maps Third
                f_mapArray = m_Emaps.getAsArray
                If Not IsNothing(f_mapArray) Then
                    For Each f_ptMap As Map In f_mapArray
                        f_length = f_ptMap.getLength
                        If f_length <> 0 Then
                            array_copy(f_ptMap.getMap(Array_), 0, f_toArray, f_offset, f_length)
                            f_offset += f_length
                            Debug.Print("Importing: " & f_ptMap.getDescription)
                        End If
                    Next
                End If
                Console.WriteLine("past the extra")
                '' Global Varibles Forth
                If Not IsNothing(f_varArray) Then
                    For Each f_ptVar As Variable In f_varArray
                        f_length = f_ptVar.getLength
                        If f_length <> 0 Then
                            array_copy(f_ptVar.getBytes(Array_), 0, f_toArray, f_offset, f_length)
                            f_offset += f_length
                        End If
                    Next
                End If

            End If
        End If
    End Function
    Friend Function mapExport(ByVal MapNo As Byte) As Byte()
        Dim array_() As Byte = Me.baseExport
        Dim f_totalLength As Integer = 0
        Dim f_toArray() As Byte = Nothing
        Dim f_length As Integer
        Dim f_tmArray() As Byte
        Dim f_offset As Integer = 0

        If MapNo >= 0 And MapNo <= 2 And UBound(array_) >= (m_dataEnd - 1) Then
            f_totalLength += m_Gvars.length + m_Fmaps.length + m_Imaps.length + m_Emaps.length
            Select Case (MapNo)
                Case 0
                    f_toArray = m_mapOne
                Case 1
                    f_toArray = m_mapTwo
                Case 2
                    f_toArray = m_mapThree
            End Select

            If Not IsNothing(f_toArray) And UBound(f_toArray) >= f_totalLength - 1 Then
                Dim f_mapArray() As Map = m_Fmaps.getAsArray
                Dim f_varArray() As Variable = m_Gvars.getAsArray
                Dim f_vq As Map = m_vqMap

                '' Fuel Maps First
                If Not IsNothing(f_mapArray) Then
                    For Each f_ptMap As Map In f_mapArray
                        f_length = f_ptMap.getLength
                        If f_length <> 0 Then
                            ReDim f_tmArray(0 To f_length - 1)
                            array_copy(f_toArray, f_offset, f_tmArray, 0, f_length)
                            f_ptMap.setMap(array_, f_tmArray)
                            f_offset += f_length
                        End If
                    Next
                End If

                '' Igntiion Maps Second
                f_mapArray = m_Imaps.getAsArray
                If Not IsNothing(f_mapArray) Then
                    For Each f_ptMap As Map In f_mapArray
                        f_length = f_ptMap.getLength
                        If f_length <> 0 Then
                            ReDim f_tmArray(0 To f_length - 1)
                            array_copy(f_toArray, f_offset, f_tmArray, 0, f_length)
                            f_ptMap.setMap(array_, f_tmArray)
                            f_offset += f_length
                        End If
                    Next
                End If

                '' Extra Maps Third
                f_mapArray = m_Emaps.getAsArray
                If Not IsNothing(f_mapArray) Then
                    For Each f_ptMap As Map In f_mapArray
                        f_length = f_ptMap.getLength
                        If f_length <> 0 Then
                            ReDim f_tmArray(0 To f_length - 1)
                            array_copy(f_toArray, f_offset, f_tmArray, 0, f_length)
                            f_ptMap.setMap(array_, f_tmArray)
                            f_offset += f_length
                            Debug.Print("Exporting: " & f_ptMap.getDescription)
                        End If
                    Next
                End If

                '' Global Varibles Forth
                If Not IsNothing(f_varArray) Then
                    For Each f_ptVar As Variable In f_varArray
                        f_length = f_ptVar.getLength
                        If f_length <> 0 Then
                            ReDim f_tmArray(0 To f_length - 1)
                            array_copy(f_toArray, f_offset, f_tmArray, 0, f_length)
                            f_ptVar.setBytes(array_, f_tmArray)
                            f_offset += f_length
                        End If
                    Next
                End If
            End If
        End If
        Return array_
    End Function
    Friend Sub baseImport(ByRef Array_() As Byte)
        If UBound(Array_) >= m_dataEnd - 1 Then
            For i As Integer = m_dataStart To m_dataEnd
                m_baseData(i - m_dataStart) = Array_(i)
            Next
        End If
    End Sub
    Friend Sub baseImport(ByVal fileName As String)
        Dim fnum As Integer = FreeFile()
        FileOpen(fnum, fileName, OpenMode.Binary)

        If LOF(fnum) <> 0 Then
            ReDim m_baseData(m_dataEnd - m_dataStart)
            Dim f_lenTo As Long = LOF(fnum)
            Dim f_offset As Long
            If LOF(fnum) = 65536 Then
                f_offset = 0
            ElseIf LOF(fnum) = 32768 And IsNothing(m_Bvars.getByName("27C256")) Then
                f_offset = 32768
            End If
            If f_lenTo - 1 > m_dataEnd Then
                f_lenTo = m_dataEnd + 1
            End If
            For i As Integer = m_dataStart - f_offset To CInt(f_lenTo - 1)
                FileGet(fnum, m_baseData(i - m_dataStart + f_offset), i + 1)
            Next
        End If
        FileClose(fnum)
    End Sub
    Friend Function baseExport() As Byte()
        If Not IsNothing(m_baseData) Then
            Dim f_export(0 To m_dataEnd) As Byte
            For i As Integer = m_dataStart To m_dataEnd
                f_export(i) = m_baseData(i - m_dataStart)
            Next
            Return f_export
        Else
            Return Nothing
        End If
    End Function
    Friend Function load(ByVal xmlFile As String) As Boolean
        Dim ret As Boolean = False
        Try
            Dim s_xml As XmlTextReader = New XmlTextReader(xmlFile)
            Me.loadVars(s_xml, "global", m_Gvars)
            s_xml.ResetState()
            Me.loadVars(s_xml, "bikirom", m_Bvars)
            'Debug.Print(m_Bvars.length)
            s_xml.ResetState()
            Me.loadMaps(s_xml, "fuel", m_Fmaps)
            s_xml.ResetState()
            Me.loadMaps(s_xml, "ignition", m_Imaps)
            s_xml.ResetState()
            Me.loadMaps(s_xml, "extra", m_Emaps)
            s_xml.ResetState()

            '' Set reference quick pointers to key maps/variables

            Dim vqAdr As Integer = m_Bvars.getByName("VQ").getAddress
            If vqAdr <> 0 Then
                m_vqMap = m_Emaps.getByAddress(vqAdr)
            End If
            m_kVar = m_Gvars.getByName("K")

            Me.setDataStart(m_Bvars.getByName("FLASHstart").getAddress)
            If Not IsNothing(m_Bvars.getByName("FLASHend")) Then Me.setDataEnd(m_Bvars.getByName("FLASHend").getAddress)
            ReDim m_baseData(0 To m_dataEnd - m_dataStart)
            ret = True
        Catch
            ret = False
        End Try
        Return ret
    End Function
    Private Sub loadVars(ByRef s_xml As XmlTextReader, ByVal node As String, ByRef ptVars As Variables)
        Dim f_description As String = ""
        Dim f_length As Byte = 1
        Dim f_multiplier As Double = 1
        Dim f_name As String = ""
        Dim f_address As Integer = 0

        If s_xml.ReadToFollowing(node) Then
            Dim f_read As XmlReader = s_xml.ReadSubtree
            Dim f_var As XmlReader
            While (f_read.Read)
                Select Case f_read.NodeType
                    Case XmlNodeType.Element
                        Select Case LCase(f_read.Name)
                            Case "variable"
                                f_var = f_read.ReadSubtree
                                f_description = ""
                                f_length = 1
                                f_multiplier = 1
                                f_name = ""
                                f_address = 0
                                While f_var.Read
                                    If f_var.NodeType = XmlNodeType.Element Then
                                        Select Case LCase(f_var.Name)
                                            Case "name"
                                                If f_var.Read Then
                                                    f_name = f_var.ReadContentAsString
                                                End If
                                            Case "description"
                                                If f_var.Read Then
                                                    f_description = f_var.ReadContentAsString
                                                End If
                                            Case "address"
                                                If f_var.Read Then
                                                    f_address = f_var.ReadContentAsInt
                                                End If
                                            Case "length"
                                                If f_var.Read Then
                                                    f_length = iByte(f_var.ReadContentAsInt)
                                                End If
                                            Case "multiplier"
                                                If f_var.Read Then
                                                    f_multiplier = f_var.ReadContentAsDouble
                                                End If
                                        End Select
                                    End If
                                End While
                                ptVars.addNode(f_name, f_description, f_address, f_multiplier, f_length)
                        End Select
                End Select
            End While
        End If
    End Sub
    Private Sub loadMaps(ByRef s_xml As XmlTextReader, ByVal Node As String, ByRef ptMaps As Maps)
        Dim f_description As String = ""
        Dim f_width As Short = 0
        Dim f_height As Short = 0
        Dim f_multiplier As Double = 1
        Dim f_widthScale As Integer = 0
        Dim f_heightScale As Integer = 0
        Dim f_widthMult As Double = 1
        Dim f_heightMult As Double = 1
        Dim f_address As Integer = 0
        Dim f_bytesize As Byte = 1

        ' Move to fist element
        If s_xml.ReadToFollowing(Node) Then
            Dim f_read As XmlReader = s_xml.ReadSubtree
            Dim f_map As XmlReader
            While (f_read.Read)
                Select Case f_read.NodeType
                    Case XmlNodeType.Element
                        Select Case LCase(f_read.Name)
                            Case "width"
                                If f_read.Read Then
                                    If f_read.NodeType = XmlNodeType.Text Then
                                        ptMaps.setWidth(CShort(f_read.ReadContentAsInt))
                                    End If
                                End If
                            Case "height"
                                If f_read.Read Then
                                    If f_read.NodeType = XmlNodeType.Text Then
                                        ptMaps.setHeight(CShort(f_read.ReadContentAsInt))
                                    End If
                                End If
                            Case "description"
                                If f_read.Read Then
                                    If f_read.NodeType = XmlNodeType.Text Then
                                        ptMaps.setDescription(f_read.ReadContentAsString)
                                    End If
                                End If
                            Case "widthscale"
                                If f_read.Read Then
                                    If f_read.NodeType = XmlNodeType.Text Then
                                        ptMaps.setWidthScale(f_read.ReadContentAsInt)
                                    End If
                                End If
                            Case "heightscale"
                                If f_read.Read Then
                                    If f_read.NodeType = XmlNodeType.Text Then
                                        ptMaps.setHeightScale(f_read.ReadContentAsInt)
                                    End If
                                End If
                            Case "widthmultiplier"
                                If f_read.Read Then
                                    If f_read.NodeType = XmlNodeType.Text Then
                                        ptMaps.setWidthMultiplier(f_read.ReadContentAsDouble)
                                    End If
                                End If
                            Case "heightmultiplier"
                                If f_read.Read Then
                                    If f_read.NodeType = XmlNodeType.Text Then
                                        ptMaps.setHeightMultiplier(f_read.ReadContentAsDouble)
                                    End If
                                End If
                            Case "marginal"
                                If f_read.Read Then
                                    If f_read.NodeType = XmlNodeType.Text Then
                                        ptMaps.setMarginal(iByte(f_read.ReadContentAsInt))
                                    End If
                                End If
                            Case "map"
                                f_map = f_read.ReadSubtree
                                f_address = 0
                                f_bytesize = 1
                                f_width = 0
                                f_height = 0
                                f_bytesize = 1
                                f_description = vbNullString
                                While f_map.Read
                                    If f_map.NodeType = XmlNodeType.Element Then
                                        Select Case LCase(f_map.Name)
                                            Case "description"
                                                If f_map.Read Then
                                                    f_description = f_map.ReadContentAsString
                                                End If
                                            Case "address"
                                                If f_map.Read Then
                                                    f_address = f_map.ReadContentAsInt
                                                End If
                                            Case "width"
                                                If f_map.Read Then
                                                    f_width = CShort(f_map.ReadContentAsInt)
                                                End If
                                            Case "height"
                                                If f_map.Read Then
                                                    f_height = CShort(f_map.ReadContentAsInt)
                                                End If
                                            Case "bytesize"
                                                If f_map.Read Then
                                                    f_bytesize = iByte(f_map.ReadContentAsInt)
                                                End If
                                        End Select
                                    End If
                                End While
                                ptMaps.addMap(f_address, f_description, f_width, f_height, f_bytesize)
                        End Select
                End Select
            End While
        End If
    End Sub

    Friend Sub setVQmap(ByVal Address_ As Integer)
        m_vqMap = Me.getEmaps.getByAddress(Address_)
    End Sub
    Public Property KvarPt() As Variable
        Get
            Return m_kVar
        End Get
        Set(ByVal value As Variable)
            m_kVar = value
        End Set
    End Property

    Friend Sub setVQmap(ByRef VQmap As Map)
        m_vqMap = VQmap
    End Sub
    Friend Sub setDataStart(ByVal Start_ As Integer)
        m_dataStart = Start_
        ReDim m_baseData(0 To m_dataEnd - m_dataStart)
    End Sub
    Friend Sub setDataEnd(ByVal End_ As Integer)
        m_dataEnd = End_
        ReDim m_baseData(0 To m_dataEnd - m_dataStart)
    End Sub
    Friend Sub setUpload()
        m_mapOne = Nothing
        m_mapTwo = Nothing
        m_mapThree = Nothing
    End Sub

    Friend Function TP_calc(ByRef Array_() As Byte, ByVal RPM As Integer, ByVal afm As Integer, ByVal rafm As Integer) As Byte
        Dim returnByte As Byte = 0
        Dim f_kmult As Double = 1
        Dim vq As Integer = VQ_Value(Array_, afm) + VQ_Value(Array_, rafm)
        If RPM > 0 And Not IsNothing(m_kVar) Then
            Dim f_mult As Variable = m_Bvars.getByName("KMULT")
            If Not IsNothing(f_mult) Then f_kmult = f_mult.getAddress
            returnByte = iByte(CLng((m_kVar.getValue(Array_) * f_kmult * (vq / 32768)) / (RPM / 12.5)))
        Else
            returnByte = 0
        End If
        Return returnByte
    End Function
    Friend Function VQ_Value(ByRef Array_() As Byte, ByVal Mvolts As Integer) As Integer
        Dim f_return As Integer = 0
        If Not IsNothing(m_vqMap) And Mvolts <= 5120 And Mvolts >= 0 Then
            Dim f_step As Integer = 5120 \ (m_vqMap.getWidth * m_vqMap.getHeight)
            Dim f_offset As Integer = Mvolts \ f_step
            f_return = m_vqMap.getIntValue(Array_, f_offset)
        End If
        Return f_return
    End Function
End Class
